Spesso, quando si lavora con grandi modelli, i dati di quest'ultimi tendono a non essere densi; come nel modello precedente, su cui abbiamo lavorato, e molto più spesso in una disposizione sparsa. I dati densi possono essere percepiti alla stessa maniera dei dati di un foglio elettronico. Normalmente, viene usato per vettori di dati con non più di due dimensioni, dove ogni colonna ed ogni riga è riempita da dati.
I dati sparsi, d'altra parte, coinvolgono tipicamente dimensioni multiple, ma non neccessariamente contengono valori per ogni combinazione di indici. Dati sparsi sono solitamente immagazzinati in un formato di tabella, dove ogni colonna rappresenta un indice o un valore di dati. Quando si lavora con ampie serie di dati sparsi, è comune lavorare con i dati in un format di tabella. Questo vi permette di saltare facilmente certe combinazioni dell'indice, che non sono valide, omettendole nella tabella.
A volte, quando formulate modelli di produzione di progettazione, la decisione coinvolge le macchine da usare per produrre i prodotti. Dato che non tutte le macchine sono disponibili in ogni impianto questo introduce una sparsità nel modello. Quando definiamo i dati e i vettori di variabili per il modello, utilizzeremo, dunque, quella sparsità per essere sicuri che la misura del modello non diventi troppo grande. Questo può essere ottenuto sia usando il comando standard WHERE (DOVE) in un vettore di dati, o usando l'operatore IN per connettere gli indici in questione.
L'operatore IN in MPL vi permette di selezionare uno degli indici di dominio da un indice multidimensionale. Per esempio, se avete un indice multidimensionale che specifica quali macchine sono disponibili in quali impianti, potete usare l'operatore IN per sommare l'eccedenza di tutte le macchine per quel particolare impianto.
INDEX plant := (p1, p2, p3, p4); machine := (m11, m12, m13, m21, m22, m31, m32, m41); PlantMach[plant,machine] := (p1.m11, p1.m12, p1.m13, p2.m21, p2.m22, p3.m31, p3.m32, p4.m41);
Nell'esempio qui sopra, abbiamo definito un indice multidimensionale chiamato PlantMach che connette gli impianti alle macchine corrispondenti.
L'indice PlantMach può, dunque, essere usato, in maniera selettiva, per scegliere solo le macchine che sono disponibili in un impianto particolare. Per esempio:
SUBJECT TO PlantCapacity[plant] : SUM(machine IN PlantMach: Produce[machine]) <= MaxCapacity[plant];
Nell'esempio qui sopra, sommiamo quanto viene prodotto in ogni macchina in quel particolare impianto. Così ci assicuriamo che la produzione totale sia circoscritta alla capacità massima.
Così come potete accumulare i dati in files esterni di dati, potete anche conservare gli indici in files esterni d'indici. Files d'indice vi permettono di conservare gli elementi in un file d'indice invece di specificarli direttamente nel modello. Quando si sta definendo un indice con un file d'indice si usi la parola chiave INDEXFILE con un nome di file invece della solita lista di elementi. Per esempio:
INDEX product := INDEXFILE("Product.idx"); month := INDEXFILE("Month.idx"); plant := INDEXFILE("Plant.idx");
Il file d'indice è un file di testo standard contenente una lista di elementi d'indice per l'indice particolare. Potete separare gli elementi nel file sia con una virgola, sia con uno spazio o con entrambi. Ad esempio, troverete, qui, un file d'indice campione per l'indice product (prodotto):
! Product.idx - Index element for the product index A1, A2, A3
Generalmente, quando si lavora con modelli sparsi, il dato cinvolto è abbastanza grande e proviene da altre applicazioni, come database comuni o desktop. Nella Sessione precedente, il dato veniva inserito nel file di modello o conservato in un file di dati denso. Quando si lavora con grandi insiemi di dati, si ha bisogno di un metodo più efficiente per importare i dati in MPL da altre applicazioni. Per questo motivo MPLpossiede la capacità di leggere i dati da un file sparso di dati. Questo file vi permette di introdurre i dati in unformato di lista standard, che è più vicino alle attuali caratteristiche dei dati, per esempio, da un database relazionale. Un esempio di file di dati sparso può essere il seguente:
ProdCost[plant, machine, product] := SPARSEFILE("ProdCost.dat");
Il file ProdCost.dat contiene i dati in una disposizione orientata a colonna con gli indici elencati nelle prime tre colonne e il corrispondente valore di dati alla fine di ogni linea come di seguito:
p1, m11, A1, 73.30, p1, m11, A2, 52.90, p1, m12, A3, 65.40, . . . p4, m41, A2, 63.30, p4, m41, A3, 53.80
Per favore si noti che, MPL vi permette, inoltre, di conservare colonne multiple di dati in un singolo file di dati sparsi. Si specifichi quali colonne aggiungendo una virgola e il numero della colonna di dati dopo il nome del file dentro le parentesi.
ProdCost[plant, machine, product] := SPARSEFILE("ProdCost.dat", 2);
L'uso di file di dati sparsi è comune nella reale modellazione. Questi file possono finire per essere abbastanza grandi, con indici multipli e contenere molti dati. Di frequente, potrete avere files d'indice multiplo e files di dati sparsi che contengono tutti i dati e lasciano il file di modello solo per contenere le dichiarazioni del modello attuale, come le variabili, la funzione obiettivo e i limiti.
In questa sessione, aggiornerete il modello così d'avere macchine multiple distribuite tra gli impianti. Userete il modello creato nella sessione 6, farete le necessarie aggiunte e aggiornamenti.
Dato che abbiamo macchine diverse in ogni impianto, il costo di produzione e il tasso di produzione ora hanno valori diversi per ogni macchina. La tabella seguente mostra una linea singola per ogni impainto, macchina, combinazione di prodotto che è applicabile.
Plant | Product | Product | ProdCost | ProdRate |
---|---|---|---|---|
p1 | m11 | A1 | $73.30 | 500 |
m11 | A2 | $52.90 | 450 | |
m12 | A3 | $65.40 | 550 | |
m13 | A3 | $47.60 | 350 | |
p2 | m21 | A1 | $79.00 | 550 |
m21 | A3 | $66.80 | 450 | |
m22 | A2 | $52.00 | 300 | |
p3 | m31 | A1 | $75.80 | 450 |
m31 | A3 | $50.90 | 300 | |
m32 | A1 | $79.90 | 400 | |
m32 | A2 | $52.10 | 350 | |
p4 | m41 | A1 | $82.70 | 550 |
m41 | A2 | $63.30 | 400 | |
m41 | A3 | $53.80 | 350 |
La decisione della produzione, quanto volgiamo produrre per ogni prdotto, deve tener conto che ora abbiamo molteplici macchine. Perciò, aggiornerete la variabile Produce così da includere l'indice machine e poi usare la condizione WHERE per escludere gli elementi non applicabili, come l'impianto p1, la macchina m11, e il prodotto A3.
Elencata qui sotto, troverete l'intera formulazione del modello per il Planning7. Le aggiunte al modello sono evidenziate in neretto per rendervi più facilmente visibili i cambiamenti al modello della Sessione 6.
TITLE Production_Planning7; INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4); toplant := plant; fromplant := plant; machine := (m11, m12, m13, m21, m22, m31, m32, m41); DATA Price[product] := (120.00, 100.00, 115.00); Demand[plant, product, month] := DATAFILE("Demand6.dat"); ProdCost[plant, machine, product] := SPARSEFILE("Produce.dat", 1); ProdRate[plant, machine, product] := SPARSEFILE("Produce.dat", 2); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[plant, product] := DATAFILE("InvtCost.dat"); InvtCapacity[plant] := (800, 400, 500, 400); ShipCost[fromplant, toplant] := DATAFILE ("ShipCost.dat"); VARIABLES Produce[plant, machine, product, month] -> Prod WHERE (ProdCost > 0); Inventory[plant, product, month] -> Invt; Sales[plant, product, month] -> Sale; Ship[product, month, fromplant, toplant] WHERE (fromplant <> toplant); MACROS TotalRevenue := SUM(plant, product, month: Price * Sales); TotalProdCost := SUM(plant, machine, product,month: ProdCost * Produce); TotalInvtCost := SUM(plant, product, month: InvtCost * Inventory); TotalShipCost := SUM(product, month, fromplant, toplant: ShipCost * Ship); TotalCost := TotalProdCost + TotalInvtCost + TotalShipCost; MODEL MAX Profit = TotalRevenue - TotalCost; SUBJECT TO ProdCapacity[plant, machine, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail; PlantBal[plant, product, month] -> PBal: SUM(machine: Produce) + Inventory[month-1] + SUM(fromplant: Ship[fromplant, toplant:=plant]) = Sales + Inventory + SUM(toplant: Ship[fromplant:=plant, toplant]); MaxInventory[plant, month] -> MaxI: SUM(product: Inventory) <= InvtCapacity; BOUNDS Sales < Demand; END
Eseguire l'applicazione MPL.
Scegliere File(Archivio) | Open(Aprire) e aprire il modello dalla sessione precedente Planning6.mpl.
Scegliere File(Archivio) | Save As (Salva come) per salvarlo come un nuovo file di modello Planning7.mpl.
Cambiare il Titolo al Modello per sottolineare che state lavorando con il modello Planning7.
TITLE Production_Planning7;
In questo modello, ogni impianto ha, ora, molteplici macchine. Per creare un indice per le macchine aggiungere la seguente definizione per l'indice machine nella sezione INDEX.
INDEX product := (A1, A2, A3); month := (Jan, Feb, Mar, Apr); plant := (p1, p2, p3, p4); toplant := plant; fromplant := plant; machine := (m11, m12, m13, m21, m22, m31, m32, m41);
Il costo di produzione e il tasso di produzione ora hanno bisogno d'includere l'indice della macchina dato che abbiamo valori di dati diversi per ogni macchina.Inoltre, visto che il dato è ora sparso, cioè non tutti gli impianti hanno tutte la macchine, accumulerete i dati in un file di dati sparsi. MPL permette di accumulare colonne di molteplici dati in un singolo file di dati sparsi. Specificate quale colonna leggre aggiungendo una virgola e il numero della colonna di dati dopo il nome del file.
Aggiornare le definizioni per i vettori di dati ProdCost e ProdRate per includere l'indice machine e cambiare i nomi del file in un nuovo file di dato sparso chiamato Produce.dat. Per il costo di produzione specificare il numero della colonna 1 dopo il nome del file e per il tasso di produzione specificare il numero della colonna 2.
DATA Price[product] := (120.00, 100.00, 115.00); Demand[plant, product, month] := DATAFILE("Demand6.dat"); ProdCost[plant, machine, product] := SPARSEFILE("Produce.dat", 1); ProdRate[plant, machine, product] := SPARSEFILE("Produce.dat", 2); ProdDaysAvail[month] := (23, 20, 23, 22); InvtCost[product] := DATAFILE("InvtCost.dat"); InvtCapacity[plant] := (800, 400, 500, 400); ShipCost[fromplant, toplant] := DATAFILE("ShipCost.dat");
Ora avete bisogno di creare il file di dati sparsi Produce.dat dai dati forniti nella descrizione del problema precedentemente in questa sessione.
Per creare i file di dati per il costo di produzione, aprire una nuova finestra di editor per il file di dati, chiamata Produce.dat e inserire quello che segue:
! ! Produce.dat - Production Cost and Rate ! ! ProdCost[plant, machine, product]: ! ProdRate[plant, machine, product]: ! p1, m11, A1, 73.30, 500, p1, m11, A2, 52.90, 450, p1, m12, A3, 65.40, 550, p1, m13, A3, 47.60, 350, p2, m21, A1, 79.00, 550, p2, m21, A3, 66.80, 450, p2, m22, A2, 52.00, 300, p3, m31, A1, 75.80, 450, p3, m31, A3, 50.90, 300, p3, m32, A1, 79.90, 400, p3, m32, A2, 52.10, 350, p4, m41, A1, 82.70, 550, p4, m41, A2, 63.30, 400, p4, m41, A3, 53.80, 350,
La variabile Produce necessita ora di avere l'indice machine nelle dichiarazioni come noi abbiamo bisogno di sapere su quale macchina ogni prodotto viene realizzato.Inoltre, dato che non tutte le macchine sono in ogni impianto, abbiamo bisogno di escludere le combinazioni dell'indice non valide. Questo viene fatto usando la condizione where sul vettore di dati ProdCost. Le combinazioni di indici sono usate solo quando ProdCost è maggiore di zero o quando si allarga la variabile Produce. Introdurre i cambiamenti alla variabile Produce come segue:
VARIABLES Produce[plant, machine, product, month] -> Prod WHERE (ProdCost > 0);
Nella macro, per il costo totale di produzione, aggiungere l'indice machine per sottolineare che la variabile Produce ora contiene l'indice machine.
MACROS TotalRevenue := SUM(plant, product, month: Price * Sales); TotalProdCost := SUM(plant, machine, product,month: ProdCost * Produce); TotalInvtCost := SUM(plant, product, month: InvtCost * Inventory); TotalShipCost := SUM(product, month, fromplant,toplant: ShipCost * Ship); TotalCost := TotalProdCost + TotalInvtCost + TotalShipCost;
Nella dichiarazione per il vincolo della capacità di produzione, l'indice machine deve essere incluso dato che ora abbiamo separato il limite della capacità per ogni macchina nell'impianto. Introdurre i cambiamenti al vincolo ProdCapacity come segue:
SUBJECT TO ProdCapacity[plant, machine, month] -> PCap: SUM(product: Produce / ProdRate) <= ProdDaysAvail;
Nel vincolo dell'equilibrio dell'impianto abbiamo ora una variabile separata Produce per ogni macchina. Dato che dobbiamo sommare insieme la produzione totale per l'impianto particolare, abbiamo bisogno di sommare sull'indice della macchina quando facciamo riferimento alla variabile Produce. Per far questo aggiungere la sommatoria seguente al vincolo PlantBal:
PlantBal[plant, product, month] -> PBal: SUM(machine: Produce) + Inventory[month-1] + SUM(fromplant: Ship[fromplant, toplant:=plant]) = Sales + Inventory + SUM(toplant: Ship[fromplant:=plant, toplant]);
Il prossimo passo sarà la risoluzione del modello 'Planning7.mpl' scegliendo Solve CPLEX dal menu Run. Se tutto procede bene MPL visualizzerà il messaggio 'Optimal Solution Found' (Trovata Soluzione Ottimale) . Se c'è una finestra con un messaggio d'errore con un errore di sintassi, per favore si controlli la formulazione inserita con il modello descritto precedentemente in questa sessione.
Userete la finestra delle definizioni del modello ancora, come nella Sessione6, per guardare le parti della soluzione che ci interessano. Per aprire le la finestra di definizioni del modello per il modello Planning7scegliere Model Definitions dal menu View.
La finestra del modello dell'abero di definizioni per il modelloPlanning7
Guardando i valori per la variabileProduce (Prodotto) fate doppio click sull'icona del prodotto dell'albero della variabile o selezionatelo e premete il bottone View (Vista). Questo visualizzerà una finestra di visuale contenente i valori della soluzione solo per la variabile Produce che sono mostrati di seguito:
VARIABLE Produce[plant,machine,product,month] : plant machine product month Activity Reduced Cost -------------------------------------------------------------------- p1 m11 A1 Jan 4300.0000 0.0000 p1 m11 A1 Feb 4200.0000 0.0000 p1 m11 A1 Mar 5487.5000 0.0000 p1 m11 A1 Apr 5300.0000 0.0000 p1 m11 A2 Jan 6480.0000 0.0000 p1 m11 A2 Feb 5220.0000 0.0000 p1 m11 A2 Mar 5411.2500 0.0000 p1 m11 A2 Apr 5130.0000 0.0000 p1 m12 A3 Feb 9049.3506 0.0000 p1 m12 A3 Mar 916.1616 0.0000 p1 m12 A3 Apr 10803.1169 0.0000 p1 m13 A3 Jan 8050.0000 0.0000 p1 m13 A3 Feb 7000.0000 0.0000 p1 m13 A3 Mar 8050.0000 0.0000 p1 m13 A3 Apr 7700.0000 0.0000 p2 m21 A1 Jan 5100.0000 0.0000 p2 m21 A1 Feb 6200.0000 0.0000 p2 m21 A1 Mar 6538.8889 0.0000 p2 m21 A1 Apr 7600.0000 0.0000 p2 m21 A3 Jan 4422.6136 0.0000 p2 m21 A3 Feb 3927.2727 0.0000 p2 m21 A3 Mar 5000.0000 0.0000 p2 m21 A3 Apr 3681.8182 0.0000 p2 m22 A2 Jan 6900.0000 0.0000 p2 m22 A2 Feb 6000.0000 0.0000 p2 m22 A2 Mar 6900.0000 0.0000 p2 m22 A2 Apr 6600.0000 0.0000 p3 m31 A1 Jan 3300.0000 0.0000 p3 m31 A1 Feb 5964.9351 0.0000 p3 m31 A1 Mar 2550.0000 0.0000 p3 m31 A1 Apr 4477.4026 0.0000 p3 m31 A3 Jan 4700.0000 0.0000 p3 m31 A3 Feb 2023.3766 0.0000 p3 m31 A3 Mar 5200.0000 0.0000 p3 m31 A3 Apr 3615.0649 0.0000 p3 m32 A1 Jan 800.0000 0.0000 p3 m32 A1 Feb 135.0649 0.0000 p3 m32 A1 Mar 2150.0000 0.0000 p3 m32 A1 Apr 1322.5974 0.0000 p3 m32 A2 Jan 7350.0000 0.0000 p3 m32 A2 Feb 6881.8182 0.0000 p3 m32 A2 Mar 6168.7500 0.0000 p3 m32 A2 Apr 6542.7273 0.0000 p4 m41 A1 Jan 4300.0000 0.0000 p4 m41 A1 Feb 4100.0000 0.0000 p4 m41 A1 Mar 5073.6111 0.0000 p4 m41 A1 Apr 4500.0000 0.0000 p4 m41 A2 Jan 2270.0000 0.0000 p4 m41 A2 Feb 5018.1818 0.0000 p4 m41 A2 Mar 2500.0000 0.0000 p4 m41 A2 Apr 5527.2727 0.0000 p4 m41 A3 Jan 3327.3864 0.0000 p4 m41 A3 Mar 2633.8384 0.0000 --------------------------------------------------------------------
La variabile Produce è ora definita su quattro indici: plant (impianto), machine(macchina), product(prodotto) e month(mese).Per ogni impianto il modello decide quale macchina è la più efficiente per produrre i prodotti in quel particolare impianto. Questa tabella può essere usata come base per un programma di produzione per l'intera compagnia.
L'altra variabile che è coinvolta nel modello è la variabile Inventory (Inventario). Se date un altro sguardo alla finestra ad albero e aprite una finestra di visuale per la variabile Inventory(Inventario) avrete i seguenti valori di soluzione:
VARIABLE Inventory[plant,product,month] : plant product month Activity Reduced Cost ----------------------------------------------------------- p1 A2 Jan 800.0000 0.0000 p2 A2 Jan 400.0000 0.0000 p3 A3 Jan 500.0000 0.0000 p4 A3 Jan 400.0000 0.0000 -----------------------------------------------------------
Come potete vedere il modello ha deciso di produrre i prodotti A2 e A3 durante Gennaio per essere sicuri di avere abbastanza tra le mani per Febbraio.
La maggior parte degli impianti stanno ora lavorando a pueno ritmo. Se date ancora uno sguardo alla finestra ad albero e aprite una finestra di visuale per il vincolo ProdCapacity avrete i seguenti valori di soluzione:
CONSTRAINT ProdCapacity[plant,machine,month] : plant machine month Slack Shadow Price ----------------------------------------------------------- p1 m12 Jan 23.0000 0.0000 p1 m12 Feb 3.9595 0.0000 p1 m12 Mar 20.2682 0.0000 p1 m12 Apr 1.2033 0.0000 p2 m21 Jan 3.6947 0.0000 -----------------------------------------------------------
Come potete vedere l'impianto p1 possiede capacità extra per la macchina m12 e l'impianto p2 possiede capacità extra per la macchina m21. A parte tutto, tutte le macchine in ogni impianto lavorano a pieno ritmo per esaudire la richiesta.